package com.seres.redis;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

import com.seres.client.annotation.TableFieldDefaultValue;
import com.seres.enums.ErrorEnum;
import com.seres.enums.RedisCacheEnum;
import com.seres.exception.ServerException;
import com.seres.listener.event.ClearTableCacheEvent;
import com.seres.util.SpringUtil;
import com.seres.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.math.BigDecimal;


@Component
@Slf4j
public class RedisTableCache {

    @Autowired
    private RedisCache redisCache;

    @Autowired
    ApplicationEventPublisher publisher;

    /**
     * 单表缓存过期时间
     */
    private static final int TABLE_CACHE_EXPIRE = 86400;


    public <T> T get(Class<T> clz, Serializable id, int... seconds) {
        T t = null;
        String key = RedisCacheEnum.TABLE.createKey(clz.getSimpleName(), id);
        String value = redisCache.getJedis().get(key);
        if (!StringUtils.isEmpty(value)) {
            t = JSONObject.parseObject(value, clz);
            t = setDefaultValue(t);
            return t;
        }
        String beanName = String.format("%sMapper", StringUtils.toLowerCaseFirstOne(clz.getSimpleName()));
        BaseMapper<T> baseMapper = SpringUtil.getBean(beanName);
        if (baseMapper == null) {
            throw new ServerException(ErrorEnum.ERROR_TABLE);
        }
        t = baseMapper.selectById(id);
        if (t != null) {
            //默认过期时间
            int exSeconds = TABLE_CACHE_EXPIRE;
            //如果手动指定不过期则不过期
            if (seconds != null && seconds.length > 0) {
                exSeconds = seconds[0];
            }
            if (exSeconds <= 0) {
                redisCache.getJedis().set(key, JSONObject.toJSONString(t));
            } else {
                redisCache.getJedis().setex(key, exSeconds, JSONObject.toJSONString(t));
            }
        }
        return t;
    }

    private <T> T setDefaultValue(T t) {
        Field[] fields = t.getClass().getDeclaredFields();
        for (Field field : fields) {
            try {
                field.setAccessible(true);
                if(field.get(t) != null){
                    continue;
                }
                TableFieldDefaultValue defaultValue = field.getDeclaredAnnotation(TableFieldDefaultValue.class);
                if (defaultValue == null) {
                    continue;
                }
                if (Integer.class.equals(field.getType())) {
                    field.set(t, Integer.valueOf(defaultValue.value()));
                } else if (Long.class.equals(field.getType())) {
                    field.set(t, Long.valueOf(defaultValue.value()));
                } else if (BigDecimal.class.equals(field.getType())) {
                    field.set(t, new BigDecimal(defaultValue.value()));
                } else if (Double.class.equals(field.getType())) {
                    field.set(t, Double.valueOf(defaultValue.value()));
                }
            } catch (Throwable e) {
                log.error("{}", e);
            }
        }
        return t;
    }


    public <T> void remove(Class<T> clz, Serializable id) {
        publisher.publishEvent(new ClearTableCacheEvent(this,clz,id));
    }
}
